package com.css.bjdt_report.executive.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.css.bjdt_report.cell.entity.Cell;
import com.css.bjdt_report.cell.entity.Cell.CellType;
import com.css.bjdt_report.cell.service.CellDataService;
import com.css.bjdt_report.cell.service.CellService;
import com.css.bjdt_report.dataSetManage.entity.ViewDataItem;
import com.css.bjdt_report.dataSetManage.service.DataItemService;
import com.css.bjdt_report.executive.Executors;
import com.css.bjdt_report.executive.Executor;
import com.css.bjdt_report.executive.entity.Exp;
import com.css.bjdt_report.executive.factory.ExecutorFactory;
import com.css.bjdt_report.executive.report.ReportRequest;
import com.css.bjdt_report.executive.report.ReportSession;
import com.css.bjdt_report.executive.util.CalcExpParser;
import com.css.bjdt_report.executive.util.ExpParser;
import com.css.bjdt_report.executive.util.SqlExpProducer;
import com.css.bjdt_report.report.entity.RptTemplateUnitRela;
import com.css.bjdt_report.report.entity.ViewRptGroupTemplate;
import com.css.bjdt_report.report.entity.ViewRptStatCategory;
import com.css.bjdt_report.report.entity.ViewRptTemplateCondition;
import com.css.bjdt_report.report.service.ReportCalcService;
import com.css.bjdt_report.report.service.ReportConditionService;
import com.css.bjdt_report.report.service.ReportStatCategoryService;
import com.css.bjdt_report.report.service.ReportTemplateManageService;
import com.css.bjdt_report.report.service.ReportTemplateUnitRelaService;

@Service
public class ReportExecuteService {
	@Autowired
	private ReportTemplateManageService reportTemplateService;
	@Autowired
	private ReportTemplateUnitRelaService reportTemplateUnitRelaService;
	@Autowired
	private ReportStatCategoryService reportStatCategoryService;
	@Autowired
	private ReportConditionService reportConditionService;
	@Autowired
	private ReportCalcService reportCalcService;
	@Autowired
	private DataItemService dataItemService;
	@Autowired
	private CellService cellService;
	@Autowired
	private CellDataService cellDataService;

	private SqlExpProducer producer = SqlExpProducer.getInstance();
	private ExpParser parser = CalcExpParser.getInstance();
	private Executors executors = Executors.getInstance();

	/**
	 * 初始化报表
	 * 
	 * @param annualId
	 */
	public void initReport(String annualId) {
		Map<String, ViewDataItem> itemMap = dataItemService.getPKAndFK();
		producer.setItemMap(itemMap);
		List<ViewRptGroupTemplate> templates = reportTemplateService.getRptTemplateByAnnualId(annualId);
		List<Cell> updateCells = new ArrayList<Cell>();
		for (ViewRptGroupTemplate template : templates) {
			List<Cell> statCells = initStatIndicator(template.getTemplateId());
			if (statCells != null && statCells.size() > 0) {
				updateCells.addAll(statCells);
			}
			List<Cell> calcCells = initCalcIndicator(template.getTemplateId());
			if (calcCells != null && calcCells.size() > 0) {
				updateCells.addAll(calcCells);
			}
			List<Cell> quoteCells = initQuoteIndicator(template.getTemplateId());
			if (quoteCells != null && quoteCells.size() > 0) {
				updateCells.addAll(quoteCells);
			}
		}
		persistReport(updateCells);
	}

	/**
	 * 生成报表数据
	 * 
	 * @param request
	 */
	public void generateReportData(ReportRequest request) {
		initIndicatorExecutor(request);
		generateIndicatorData(request);
	}

	/**
	 * 初始化报表取值器
	 * 
	 * @param request
	 */
	private void initIndicatorExecutor(ReportRequest request) {
		String[] templateIds = request.getTemplateIds().toArray(new String[0]);
		for (String templateId : templateIds) {
			List<Cell> cells = cellService.getCellStrategyByTemplateId(templateId);
			for (Cell cell : cells) {
				String strategyClassName = cell.getStrategyClassName();
				if(strategyClassName != null){
					Executor executor = ExecutorFactory.create(strategyClassName, false);
					if (executor != null) {
						executor.init(cell, request.getSession());
					}					
				}
			}
		}
	}

	/**
	 * 生成指标数据
	 * 
	 * @param request
	 */
	private void generateIndicatorData(ReportRequest request) {
		//一个批次请求对应一个session,可能会启动多个取值线程,但多个线程共享一个session
		ReportSession session = request.getSession();
		SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
		session.put(ReportSession.REPORT_CACHE, "startTime", format.format(request.getStartTime()));
		session.put(ReportSession.REPORT_CACHE, "endTime", format.format(request.getEndTime()));
		session.put(ReportSession.REPORT_CACHE, "fullName", request.getReportDzzName());
		session.put(ReportSession.REPORT_CACHE, "relMan", request.getReportMan());
		executors.setSession(session);
		cellDataService.createTable(request.getAnnualId());
		List<RptTemplateUnitRela> templateUnitRelas = reportTemplateUnitRelaService.getTemplateUnitRela(request);
		List<String> dzzIds = request.getDzzIds();
		for (String dzzId : dzzIds) {
			List<RptTemplateUnitRela> newtemplateUnitRelas = reportTemplateUnitRelaService.cloneTemplateUnitRela(dzzId, templateUnitRelas);
			session.put(ReportSession.REPORT_CACHE, "unit", dzzId);
			executors.execute(newtemplateUnitRelas, request.isSyn());
		}
	}

	/**
	 * 初始化统计类型指标
	 * 
	 * @param templateId
	 * @return
	 */
	private List<Cell> initStatIndicator(String templateId) {
		Map<String, List<ViewRptTemplateCondition>> conditionMap = reportConditionService.buildConditionMapByTemplateId(templateId);
		producer.setConditionMap(conditionMap);
		List<Cell> statCells = cellService.getCellsByTemplateIdAndType(templateId, CellType.stat);
		List<ViewRptStatCategory> statCategorys = reportStatCategoryService.getStatCategoryByTemplateId(templateId);
		fillCellStatCategory(statCells, statCategorys);
		for (Cell statCell : statCells) {
			producer.produceSqlExp(statCell);
			statCell.setCellLevel(99999);
		}
		return statCells;
	}

	/**
	 * 初始化计算类型指标
	 * 
	 * @param templateId
	 * @return
	 */
	private List<Cell> initCalcIndicator(String templateId) {
		Map<String, List<Exp>> calcMap = reportCalcService.buildReportCalcMapByTemplateId(templateId);
		parser.setExpMap(calcMap);
		List<Cell> calcCells = cellService.getCellsByTemplateIdAndType(templateId, CellType.calc);
		for (Cell calcCell : calcCells) {
			parser.parseExp(calcCell);
		}
		return calcCells;
	}

	/**
	 * 初始化引用类型指标
	 * 
	 * @param templateId
	 * @return
	 */
	private List<Cell> initQuoteIndicator(String templateId) {
		List<Cell> quoteCells = cellService.getCellsByTemplateIdAndType(templateId, CellType.quote);
		for (Cell quoteCell : quoteCells) {
			quoteCell.setCellLevel(99999);
		}
		return quoteCells;
	}

	/**
	 * 根据绝对起始行和绝对终止行与绝对起始列和绝对终止列,为每个指标设置统计类别
	 * 
	 * @param statCells
	 * @param statCategorys
	 */
	private void fillCellStatCategory(List<Cell> statCells, List<ViewRptStatCategory> statCategorys) {
		for (ViewRptStatCategory statCategory : statCategorys) {
			int startRowNum = Integer.parseInt(statCategory.getAbsStartRow());
			int endRowNum = Integer.parseInt(statCategory.getAbsEndRow());
			int startColNum = Integer.parseInt(statCategory.getAbsStartCol());
			int endColNum = Integer.parseInt(statCategory.getAbsEndCol());
			List<Integer> rowlist = new ArrayList<Integer>();
			List<Integer> collist = new ArrayList<Integer>();
			for (int i = startRowNum; i <= endRowNum; i++) {
				rowlist.add(i);
			}
			for (int j = startColNum; j <= endColNum; j++) {
				collist.add(j);
			}
			Integer[] rowRange = rowlist.toArray(new Integer[0]);
			Integer[] colRange = collist.toArray(new Integer[0]);
			for (Cell statCell : statCells) {
				if (ArrayUtils.contains(rowRange, statCell.getAbsRowNum()) && ArrayUtils.contains(colRange, statCell.getAbsColNum())) {
					statCell.setStatCategory(statCategory);
				}
			}
		}
	}

	private void persistReport(List<Cell> updateCells) {
		cellService.update(updateCells);
		producer.destory();
		parser.destory();
		updateCells.clear();
		updateCells = null;
	}
}
